package com.hzw.saas.service.rbac.service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.rbac.IRoleService;
import com.hzw.saas.api.rbac.IUserRoleService;
import com.hzw.saas.api.rbac.bo.RoleBO;
import com.hzw.saas.api.rbac.bo.RoleDetailBO;
import com.hzw.saas.api.rbac.enums.PermSysEnum;
import com.hzw.saas.api.rbac.query.RoleAddQuery;
import com.hzw.saas.api.rbac.query.RoleUpdateQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.config.util.PageUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.rbac.IRolePermissionService;
import com.hzw.saas.service.rbac.mapper.RoleMapper;
import com.hzw.saas.service.rbac.model.Role;
import com.hzw.saas.service.rbac.model.RolePermission;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zzl
 * @since 08/30/2021
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService, IService<Role> {

    @Resource
    private IRolePermissionService rolePermissionService;
    @Resource
    private IUserRoleService userRoleService;

    @Override
    public IPage<RoleBO> pageList(PageParam pageParam, Integer sys, String fuzzyRoleName) {
        IPage<Role> page = super.lambdaQuery()
            .eq(Role::getSys, sys)
            .like(StrUtil.isNotBlank(fuzzyRoleName), Role::getName, fuzzyRoleName)
            .orderByAsc(Role::getCreateTime)
            .page(pageParam.convert());
        return PageUtils.convert(page, RoleBO.class);
    }

    @Override
    public RoleDetailBO get(String pid) {
        Role entity = super.getById(pid);
        if (Objects.isNull(entity))
            return null;
        List<RolePermission> rolePermissions = rolePermissionService.lambdaQuery()
            .select(RolePermission::getPermId)
            .eq(RolePermission::getRoleId, entity.getPid())
            .list();
        List<String> permIds = rolePermissions.stream()
            .map(RolePermission::getPermId)
            .sorted()
            .collect(Collectors.toList());
        RoleDetailBO bo = MapperUtil.nf().map(entity, RoleDetailBO.class);
        bo.setPermIds(permIds);
        return bo;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public RoleDetailBO add(RoleAddQuery query) {
        // 校验参数
        PermSysEnum.assertValid(query.getSys());
        // 增加角色
        Role entity = MapperUtil.nf().map(query, Role.class);
        entity.setPid(SnowFlakeUtil.nextIdStr());
        super.save(entity);
        // 增加角色与权限关联
        rolePermissionService.updateRolePermissions(query.getSys(), entity.getPid(), query.getPermIds());
        // return
        RoleDetailBO result = MapperUtil.nf().map(query, RoleDetailBO.class);
        result.setPid(entity.getPid());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(RoleUpdateQuery query) {
        // 校验参数
        AssertUtil.assertThrow("pid不可为空", StrUtil.isBlank(query.getPid()));
        if (Objects.nonNull(query.getSys())) {
            PermSysEnum.assertValid(query.getSys());
        }
        // 更新角色信息
        Role entity = MapperUtil.nf().map(query, Role.class);
        super.updateById(entity);
        // 更新角色与权限关联
        rolePermissionService.updateRolePermissions(query.getSys(), query.getPid(), query.getPermIds());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String pid) {
        AssertUtil.assertThrow("pid不可为空", StrUtil.isBlank(pid));
        // 删除角色
        super.removeById(pid);
        // 删除角色与权限关联
        rolePermissionService.lambdaUpdate().eq(RolePermission::getRoleId, pid).remove();
        // 删除角色与用户关联
        userRoleService.deleteRole(pid);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatch(List<String> pids) {
        if (CollectionUtil.isEmpty(pids))
            return true;
        // 批量删除角色
        super.lambdaUpdate()
            .in(Role::getPid, pids)
            .remove();
        // 批量删除角色与权限关联
        rolePermissionService
            .lambdaUpdate()
            .in(RolePermission::getRoleId, pids)
            .remove();
        // 批量删除角色与用户关联
        userRoleService.deleteRoles(pids);
        return true;
    }

}
